package srdb.migration.schema.metadata;

import java.util.ArrayList;
import java.util.List;

import srdb.migration.Utility;
import srdb.migration.common.MTKConstants;

public class Table extends DBObject {
	private String tableName = null;
	private ColumnList columns = null;
	private Schema parentSchema = null;
	private String targetSchemaName = null;
	private int maxRowSize = 0;
	private boolean hasLargeObject = false;
	private boolean dataLoadFailure = false;
	private String whereClause = null;
	private boolean creationFailure;
	private String oid = null;
	private List<EnumType> enumTypes = new ArrayList();

	private int batchFailureCount = 0;

	private String columnsFilterList = null;

	private boolean partitioned = false;
	private MTKConstants.TablePartitionType partitionType;
	private MTKConstants.TablePartitionType subPartitionType;
	private ColumnList partitionKeyCols;
	private ColumnList subPartitionKeyCols;
	private ArrayList<TablePartition> partitions;
	private ArrayList<TablePartitionSubPartition> subPartitions;
	private String comments = null;

	private boolean relHasOIDs = false;
	private String fillFactor;
	private ArrayList<Table> inheritedFromList = new ArrayList();
	private boolean isInherited = false;
	private boolean hasCheckConst = false;

	private int pgTextColSize = 1024;

	public void resetBatchFailureCount() {
		this.batchFailureCount = 0;
	}

	public void incrementBatchFailureCount() {
		this.batchFailureCount += 1;
	}

	public int getBatchFailureCount() {
		return this.batchFailureCount;
	}

	public String getOid() {
		return this.oid;
	}

	public void setOid(String oid) {
		this.oid = oid;
	}

	public boolean isHasCheckConst() {
		return this.hasCheckConst;
	}

	public void setHasCheckConst(boolean hasCheckConst) {
		this.hasCheckConst = hasCheckConst;
	}

	public int getPgTextColSize() {
		return this.pgTextColSize;
	}

	public void setPgTextColSize(int pgTextColSize) {
		if (pgTextColSize > this.pgTextColSize) {
			this.maxRowSize += pgTextColSize - this.pgTextColSize;
			this.pgTextColSize = pgTextColSize;
		}
	}

	public String getFillFactor() {
		return this.fillFactor;
	}

	public void setFillFactor(String fillFactor) {
		this.fillFactor = fillFactor;
	}

	public boolean isInherited() {
		return this.isInherited;
	}

	public void setIsInherited(boolean isInherited) {
		this.isInherited = isInherited;
	}

	public ArrayList<Table> getInheritedFromList() {
		return this.inheritedFromList;
	}

	public Table() {
	}

	public Table(Schema parentSchema, String tableName, String targetSchemaName) {
		this.parentSchema = parentSchema;
		this.tableName = tableName;
		this.targetSchemaName = targetSchemaName;
	}

	public String getName() {
		return this.tableName;
	}

	public boolean isPartitioned() {
		return this.partitioned;
	}

	public void setPartitioned(boolean partitioned) {
		this.partitioned = partitioned;
	}

	public MTKConstants.TablePartitionType getPartitionType() {
		return this.partitionType;
	}

	public MTKConstants.TablePartitionType getSubPartitionType() {
		return this.subPartitionType;
	}

	public void setPartitionType(MTKConstants.TablePartitionType partitionType) {
		this.partitionType = partitionType;
	}

	public void setSubPartitionType(
			MTKConstants.TablePartitionType subPartitionType) {
		this.subPartitionType = subPartitionType;
	}

	public ColumnList getPartitionKeyCols() {
		return this.partitionKeyCols;
	}

	public ColumnList getSubPartitionKeyCols() {
		return this.subPartitionKeyCols;
	}

	public void setPartitionKeyCols(ColumnList partitionKeyCols) {
		this.partitionKeyCols = partitionKeyCols;
	}

	public void setSubPartitionKeyCols(ColumnList subPartitionKeyCols) {
		this.subPartitionKeyCols = subPartitionKeyCols;
	}

	public ArrayList<TablePartition> getPartitions() {
		return this.partitions;
	}

	public void addPartition(String partitionName, String partitionHighValue) {
		if (this.partitions == null) {
			this.partitions = new ArrayList();
		}

		TablePartition tablePartition = new TablePartition(partitionName,
				partitionHighValue);
		this.partitions.add(tablePartition);
	}

	public ArrayList<TablePartitionSubPartition> getSubPartitions() {
		return this.subPartitions;
	}

	public void addSubPartition(String subPartitionName,
			String partitionHighValue, String partitionName) {
		if (this.subPartitions == null) {
			this.subPartitions = new ArrayList();
		}

		TablePartitionSubPartition tableSubPartition = new TablePartitionSubPartition(
				subPartitionName, partitionHighValue, partitionName);
		this.subPartitions.add(tableSubPartition);
	}

	public String getEDBCompatibleName() {
		if ((Utility.hasValidEDBIdentifierPattern(this.tableName))
				&& (this.tableName.toUpperCase().equals(this.tableName))) {
			return this.tableName.toLowerCase();
		}

		return this.tableName;
	}

	public String getORACompatibleName() {
		if ((Utility.isValidOracleIdentifier(this.tableName))
				&& (this.tableName.toLowerCase().equals(this.tableName))) {
			return this.tableName.toUpperCase();
		}

		return this.tableName;
	}

	public String getFullName() {
		return this.parentSchema.getName() + "." + this.tableName;
	}

	public String getFullName(boolean quoted) {
		return this.parentSchema.getName(quoted) + "." + this.tableName;
	}

	public String getTargetSchemaQualifiedName() {
		return this.targetSchemaName + "." + this.tableName;
	}

	public String getTargetSchemaFullyQualifiedName(
			MTKConstants.DATABASE_TYPE sourceDBType,
			MTKConstants.DATABASE_TYPE targetDBType, boolean escapeSingleQuote) {
		String tempTableName = this.tableName;

		if (!this.tableName.startsWith("\"")) {
			if ((sourceDBType == MTKConstants.DATABASE_TYPE.ORACLE||sourceDBType == MTKConstants.DATABASE_TYPE.DB2)
					&& ((targetDBType == MTKConstants.DATABASE_TYPE.ENTERPRISEDB) || (targetDBType == MTKConstants.DATABASE_TYPE.SRDB))
					&& (Utility.hasValidEDBIdentifierPattern(tempTableName))
					&& (tempTableName.toUpperCase().equals(tempTableName))) {
				tempTableName = tempTableName.toLowerCase();
			}

			if (Utility.isCaseSensitive(tempTableName, targetDBType)) {
				tempTableName = "\"" + tempTableName + "\"";
			}

		}

		String fqn = (Utility.isCaseSensitive(this.targetSchemaName,
				targetDBType)) && (!this.targetSchemaName.startsWith("\"")) ? "\""
				+ this.targetSchemaName + "\""
				: this.targetSchemaName;
		fqn = fqn + "." + tempTableName;

		if ((escapeSingleQuote) && (fqn.contains("'"))) {
			fqn = fqn.replace("'", "''");
		}

		return fqn;
	}

	public String getTargetTableName(MTKConstants.DATABASE_TYPE sourceDBType,
			MTKConstants.DATABASE_TYPE targetDBType, boolean escapeSingleQuote) {
		String tempTableName = this.tableName;

		if (!this.tableName.startsWith("\"")) {
			if ((sourceDBType == MTKConstants.DATABASE_TYPE.ORACLE)
					&& (targetDBType == MTKConstants.DATABASE_TYPE.ENTERPRISEDB)
					&& (Utility.hasValidEDBIdentifierPattern(tempTableName))
					&& (tempTableName.toUpperCase().equals(tempTableName))) {
				tempTableName = tempTableName.toLowerCase();
			}

			if (Utility.isCaseSensitive(tempTableName, targetDBType)) {
				tempTableName = "\"" + tempTableName + "\"";
			}
		}

		if ((escapeSingleQuote) && (tempTableName.contains("'"))) {
			tempTableName = tempTableName.replace("'", "''");
		}

		return tempTableName;
	}

	public String getFullName(String schemaName) {
		return schemaName + "." + this.tableName;
	}

	public ColumnList getColumns() {
		return this.columns;
	}

	public void addColumn(Column column) {
		if (this.columns == null) {
			this.columns = new ColumnList();
		}
		this.columns.add(column);

		this.maxRowSize += column.getBufferStorageSize();

		if ((column.isLargeObject()) || (column.isClob()) || (column.isNClob())) {
			this.hasLargeObject = true;
		}
	}

	public String getSelectSQL() {
		String sql = "SELECT ";
		String colName = null;

		for (int i = 0; i < this.columns.size(); i++) {
			colName = this.columns.get(i).getName();

			sql = sql + colName;
			if (i < this.columns.size() - 1)
				sql = sql + ", ";
		}
		sql = sql + " FROM " + this.parentSchema.getName(true) + "."
				+ this.tableName;

		if (this.whereClause != null) {
			sql = sql + " WHERE " + this.whereClause;
		}

		return sql;
	}

	public String getRowIdSelectSql(){
		String sql = "SELECT ";
		String colName = null;

		sql = sql + "ROWID FROM " + this.parentSchema.getName(true) + "."
				+ this.tableName;

		if (this.whereClause != null) {
			sql = sql + " WHERE " + this.whereClause;
		}

		return sql;
	}

	public String getSelectSQL(MTKConstants.DATABASE_TYPE sourceDatabaseType) {
		String sql = "SELECT ";
		String colName = null;
		Column column = null;
		boolean oraXMLTypeFlag = false;

		for (int i = 0; i < this.columns.size(); i++) {
			column = this.columns.get(i);
			colName = column.getName();

			if ((column.isCaseSensitive()) && (colName.startsWith("\""))
					&& (colName.endsWith("\""))) {
				colName = colName.substring(1, colName.length() - 1);
			}

			colName = Utility.escape(colName, sourceDatabaseType);

			if ((sourceDatabaseType == MTKConstants.DATABASE_TYPE.ORACLE)
					&& (column.isXML())) {
				sql = sql + "t." + colName + ".getStringVal()";
				oraXMLTypeFlag = true;
			} else if ((sourceDatabaseType == MTKConstants.DATABASE_TYPE.ORACLE)
					&& (column.isRowID())) {
				sql = sql + "ROWIDTOCHAR(" + colName + ")";
			} else {
				sql = sql + colName;
			}

			if (i < this.columns.size() - 1) {
				sql = sql + ", ";
			}
		}

		sql = sql
				+ " FROM "
				+ Utility.escape(this.parentSchema.getName(),
						sourceDatabaseType) + "."
				+ Utility.escape(this.tableName, sourceDatabaseType);

		if (oraXMLTypeFlag) {
			sql = sql + " t ";
		}

		if (this.whereClause != null) {
			sql = sql + " WHERE " + this.whereClause;
		}
		System.out.println(sql);
		return sql;
	}

	public int getMaxRowSize() {
		return this.maxRowSize;
	}

	public boolean hasLargeObject() {
		return this.hasLargeObject;
	}

	public boolean hasDataLoadFailure() {
		return this.dataLoadFailure;
	}

	public void dataLoadFailed() {
		this.dataLoadFailure = true;
	}

	public boolean isCreationFailure() {
		return this.creationFailure;
	}

	public void setCreationFailure(boolean creationFailure) {
		this.creationFailure = creationFailure;
	}

	public String getWhereClause() {
		return this.whereClause;
	}

	public void setWhereClause(String whereClause) {
		this.whereClause = whereClause;
	}

	public String getTargetSchemaName() {
		return this.targetSchemaName;
	}

	public Schema getParentSchema() {
		return this.parentSchema;
	}

	public int getLargeObjectsColumnCount() {
		int lobjColCount = 0;

		for (int i = 0; i < this.columns.size(); i++) {
			if (this.columns.get(i).isLargeObject()) {
				lobjColCount++;
			}
		}

		return lobjColCount;
	}

	public int getBLOBColumnCount() {
		int blobColCount = 0;

		for (int i = 0; i < this.columns.size(); i++) {
			if (this.columns.get(i).isBlob()) {
				blobColCount++;
			}
		}

		return blobColCount;
	}

	public int getCLOBColumnCount() {
		int clobColCount = 0;

		for (int i = 0; i < this.columns.size(); i++) {
			if (this.columns.get(i).isClob()) {
				clobColCount++;
			}
		}

		return clobColCount;
	}

	public boolean hasColumn(String colName) {
		for (int i = 0; i < this.columns.size(); i++) {
			if (Utility.removeEnclosingQuotes(this.columns.get(i).getName())
					.equals(colName)) {
				return true;
			}
		}

		return false;
	}

	public DBObject getParent() {
		return null;
	}

	public String getSchema() {
		return this.parentSchema == null ? null : this.parentSchema.getName();
	}

	public String getComments() {
		return this.comments;
	}

	public void setComments(String comments) {
		this.comments = comments;
	}

	public void setRelHasOIDs(boolean relHasOIDs) {
		this.relHasOIDs = relHasOIDs;
	}

	public boolean isRelHasOIDs() {
		return this.relHasOIDs;
	}

	public String getColumnsFilterList() {
		return this.columnsFilterList;
	}

	public void setColumnsFilterList(String columnsFilterList) {
		this.columnsFilterList = columnsFilterList;
	}

	public void addEnumType(EnumType enumType) {
		this.enumTypes.add(enumType);
	}

	public int getEnumTypesCount() {
		return this.enumTypes.size();
	}

	public EnumType getEnumType(int index) {
		if (index >= this.enumTypes.size()) {
			return null;
		}
		return (EnumType) this.enumTypes.get(index);
	}

	public boolean isEnum(String typeName) {
		for (int i = 0; i < this.enumTypes.size(); i++) {
			if (((EnumType) this.enumTypes.get(i)).getName().equals(typeName)) {
				return true;
			}
		}
		return false;
	}

	public class TablePartitionSubPartition {
		private String subPartitionName;
		private String subPartitionHighValue;
		private String partitionName;

		public TablePartitionSubPartition(String subPartitionName,
				String subPartitionHighValue, String partitionName) {
			this.subPartitionName = subPartitionName;
			this.subPartitionHighValue = subPartitionHighValue;
			this.partitionName = partitionName;
		}

		public String getSubPartitionName() {
			return this.subPartitionName;
		}

		public String getSubPartitionHighValue() {
			return this.subPartitionHighValue;
		}

		public String getPartitionName() {
			return this.partitionName;
		}
	}

	public class TablePartition {
		private String partitionName;
		private String partitionHighValue;

		public TablePartition(String partitionName, String partitionHighValue) {
			this.partitionName = partitionName;
			this.partitionHighValue = partitionHighValue;
		}

		public String getPartitionName() {
			return this.partitionName;
		}

		public String getPartitionHighValue() {
			return this.partitionHighValue;
		}
	}
}

/*

 */